#include "travls.h"

Individual::Individual()
{
	distance = 0;
	map = NULL;
	for(int i=0;i<CITY_NUM;i++)
	{
		genome[i]=0;
	}
}
Individual::Individual(Map* m)
{
	map = m;
	for(int i=0;i<CITY_NUM;i++)
	{
		#ifndef START_HEUR
				genome[i]=i;
		#endif
		#ifdef START_HEUR
				genome[i]=(m->getClosestHeurPath()[i]);
		#endif
	}
	#ifndef START_HEUR
		for(int i=0;i<CITY_NUM;i++)
		{
			//create random new genomes for new populations
			int swap = rand() % CITY_NUM;
			int temp = genome[swap];
			genome[swap]=genome[i];
			genome[i]=temp;
		}
	#endif
	distance = updateDistance();
}
Individual::Individual(Map* m, Individual copy)
{
	map = m;
	for(int i=0;i<CITY_NUM;i++)
	{
		genome[i]=copy.genome[i];
	}
	distance = updateDistance();
}
double Individual::updateDistance()
{
	double distance = 0;
	for(int i=0;i<CITY_NUM -1 ;i++)
	{
		distance += map->getCoord(genome[i]).distance( map->getCoord( genome[i+1] ));
	}
	distance += map->getCoord(genome[CITY_NUM -1]).distance( map->getCoord( genome[0] ));
	return distance;
}
Individual Individual::swapGenome()
{
	int swapCount = 1;
	if( rand()%100+1 < SWAPMORE_CHANCE)
		swapCount = rand()%SWAPMORE_MAX +1;
	Individual newInd(map, *this);

	for(int i=0;i<swapCount;i++)
	{
		int swap1 = rand() % CITY_NUM, swap2 = rand() % CITY_NUM;
		int temp = newInd.genome[swap1];
		newInd.genome[swap1] = newInd.genome[swap2];
		newInd.genome[swap2] = temp;
	}

	newInd.distance = newInd.updateDistance();
	return newInd;
}
Individual Individual::insertGenome()
{
	if ((rand() % 100 +1) > INSERT_CHANCE )
	{
		return *this;
	};
	Individual newInd(map, *this);
	if ((rand() % 100 +1) > INSERT_CONTINUE )
	{
		bool loop = false;
		int insertCity = rand() % CITY_NUM;
		int insertDistance = (rand() % (CITY_NUM-1)) +1;
		int count=0;

		int temp = newInd.genome[insertCity];
		while(count<insertDistance && insertCity+count+1 < CITY_NUM)
		{
			newInd.genome[insertCity + count] = newInd.genome[insertCity + count + 1];
			count++;
		}
		if(count<insertDistance)
		{
			newInd.genome[CITY_NUM-1]=newInd.genome[0];
			count++;
			loop = true;
		}
		int startIndex =0;
		while(count<insertDistance)
		{
			newInd.genome[startIndex]=newInd.genome[startIndex+1];
			count++;
			startIndex++;
		}
		if(loop)
		{
			newInd.genome[startIndex]=temp;
		}
		else
		{
			newInd.genome[insertCity + count]=temp;
		}
#if 0 //old
		//Individual newInd(map, *this);
		int insert1 = rand() % CITY_NUM, insert2 = rand() % CITY_NUM;

		while (insert1 == insert2)
		{
			insert1 = rand() % CITY_NUM;
			insert2 = rand() % CITY_NUM;
		}
		if(insert1 > insert2)
		{
			int temp = insert1;
			insert1 = insert2;
			insert2 = temp;
		}
		int temp = newInd.genome[insert1];

		for(int i=insert1;i<insert2-1;i++)
		{
			newInd.genome[i] = newInd.genome[i+1];
		}
		newInd.genome[insert2-1] = temp;
		//return *this;
#endif
	}
	else
	{
		int randCount = rand() % INSERT_CONTINUE_MAX +1;
		for(int i=0;i<randCount;i++)
		{
			bool loop = false;
			int insertCity = rand() % CITY_NUM;
			int insertDistance = (rand() % (CITY_NUM-1)) +1;
			int count=0;

			int temp = newInd.genome[insertCity];
			while(count<insertDistance && insertCity+count+1 < CITY_NUM)
			{
				newInd.genome[insertCity + count] = newInd.genome[insertCity + count + 1];
				count++;
			}
			if(count<insertDistance)
			{
				newInd.genome[CITY_NUM-1]=newInd.genome[0];
				count++;
				loop = true;
			}
			int startIndex =0;
			while(count<insertDistance)
			{
				newInd.genome[startIndex]=newInd.genome[startIndex+1];
				count++;
				startIndex++;
			}
			if(loop)
			{
				newInd.genome[startIndex]=temp;
			}
			else
			{
				newInd.genome[insertCity + count]=temp;
			}
#if 0 //old
			int insert1 = rand() % CITY_NUM, insert2 = rand() % CITY_NUM;

			while (insert1 == insert2)
			{
				insert1 = rand() % CITY_NUM;
				insert2 = rand() % CITY_NUM;
			}
			if(insert1 > insert2)
			{
				int temp = insert1;
				insert1 = insert2;
				insert2 = temp;
			}
			int temp = newInd.genome[insert1];

			for(int i=insert1;i<insert2-1;i++)
			{
				newInd.genome[i] = newInd.genome[i+1];
			}
			newInd.genome[insert2-1] = temp;
#endif
		}

	}
	newInd.distance = newInd.updateDistance();
	return newInd;
}